//============================================================================================
/**
 * @file	bong_evt.c
 * @brief	フィールドでのボングリ入手アニメイベント処理など
 * @author	Nozomu Saito
 * @date	2008.06.05
 *
 * モジュール名：BongEvt
 */
//============================================================================================

#include "bong_evt.h"
#include "field_event.h"

#include "fieldmap.h"
#include "field/location.h"

#include "zonedata.h"
#include "mapdefine.h"
#include "eventdata.h"		//ゾーン毎のイベントデータ参照のため

#include "system/snd_tool.h"
#include "system/brightness.h"
#include "system/pm_rtc.h"
#include "system/wipe.h"
#include "system/window.h"

#include "map_tool.h"

#include "field_3d_anime_ev.h"

#include "script.h"

#include "bong_sys.h"

///初期化、ロード時に立てるビット
#define BONG_FLDOBJ_INIT_STA_BIT_ON \
(FLDOBJ_STA_BIT_ZONE_DEL_NOT|FLDOBJ_STA_BIT_HEIGHT_VANISH_OFF)
///初期化、ロード時に下ろすビット
#define BONG_FLDOBJ_INIT_STA_BIT_OFF \
(FLDOBJ_STA_BIT_PAUSE_DIR|FLDOBJ_STA_BIT_PAUSE_ANM)

#define FRUIT_FLY_ANM_SYNC	(16)

//↓ボングリの実発射アニメ　本当は10フレームあるが、
//木の実を吐き出すフレームは8フレあたりからなので、
//実を出すタイミングもそれにあわせる
#define BONG_SHOT_FRAME	(8)
//↓実を吐き出す絵に合わせて、実の位置を調整
#define START_Y_OFS	(FX32_ONE*12)

#define SWAY_FRAME	(16)
#define SWAY_COUNT	(2)

#define PLAYER_SHAKE_FRAME	(24)	//アニメの長さに依存

typedef enum {
	SEQ_BONG_PLAYER_ANM,
	SEQ_BONG_SWAY_INIT,
	SEQ_BONG_SWAY,
	SEQ_BONG_INIT,
	SEQ_BONG_FRUIT_ADD,
	SEQ_BONG_FRUIT_ADD_WAIT,
	SEQ_BONG_TREE_ADD,
	SEQ_BONG_TREE_CHANGE_WAIT,
	SEQ_BONG_SHOT_ANM,
	SEQ_BONG_FRUIT_ANM,
	SEQ_BONG_END,
}SEQ_BONG;

typedef struct EV_BONG_FRUIT_WORK_tag
{
	int Seq;
	FIELD_OBJ_PTR FldObj;
	FIELD_OBJ_PTR BongTreeObj;
	int AnmCount;
	int FruitY;
	VecFx32 AddVec;
	s16 ShotFrame;
	s8 SwayFrame;
	u8 SwayCount;

	u16 *ReturnCode;

}EV_BONG_FRUIT_WORK;

static BOOL GMEVENT_GetBonguri(GMEVENT_CONTROL * event);
static FIELD_OBJ_PTR AddFruitOBJ( CONST_FIELD_OBJ_SYS_PTR fos,
		int obj, int x, int z);
static BOOL FruitAnmMain(EV_BONG_FRUIT_WORK * ebw);

static BOOL GMEVENT_ShakePlayer(GMEVENT_CONTROL * event);

static const s8 FlyY[FRUIT_FLY_ANM_SYNC] =
{
	4, 3, 3, 2, 2, 1, 1, 0,	//ｙ方向に+16ユニット移動
	0,-1,-2,-3,-4,-5,-6,-7,//ｙ方向に-16ユニット-START_Y_OFS分移動
};

//-------------------------------------------------------------------------
/**
 * @brief	イベント呼び出し
 *
 * @param	fsys			フィールドシステムポインタ
 * @param	fldobjBong		ボングリフィールドOBJ
 * @param	*rc				リターンコードポインタ
 *
 * @retval	none
 */
//-------------------------------------------------------------------------
void BongEvt_CallGetEvt(FIELDSYS_WORK * fsys, FIELD_OBJ_PTR fldobjBong, u16 *rc)
{
	EV_BONG_FRUIT_WORK * ebw;
	ebw = sys_AllocMemory(HEAPID_EVENT, sizeof(EV_BONG_FRUIT_WORK));
	//メモリクリア
	MI_CpuClear8( ebw, sizeof(EV_BONG_FRUIT_WORK) );
	ebw->Seq = SEQ_BONG_PLAYER_ANM;
	ebw->BongTreeObj = fldobjBong;
	ebw->ReturnCode = rc;
	FieldEvent_Call(fsys->event, GMEVENT_GetBonguri, ebw);
}

//--------------------------------------------------------------
/**
 * ボングリ入手アニメイベント
 * @param	event
 * @retval	BOOL	TRUEでイベント終了
 */
//--------------------------------------------------------------
static BOOL GMEVENT_GetBonguri(GMEVENT_CONTROL * event)
{
	FIELDSYS_WORK * fsys = FieldEvent_GetFieldSysWork(event);
	EV_BONG_FRUIT_WORK * ebw = FieldEvent_GetSpecialWork(event);

	switch (ebw->Seq) {
	case SEQ_BONG_PLAYER_ANM:
		if (!BongSys_IsGrow(fsys, ebw->BongTreeObj)){
			*(ebw->ReturnCode) = 0;
			ebw->Seq = SEQ_BONG_END;
			break;
		}else{
			int *frame = sys_AllocMemoryLo(HEAPID_WORLD, sizeof(int));
			FieldEvent_Call(event, GMEVENT_ShakePlayer, frame);
		}
		//シーケンス変更
		ebw->Seq = SEQ_BONG_SWAY_INIT;
		break;
	case SEQ_BONG_SWAY_INIT:
		//ボングリの木ポーズ解除
		FieldOBJ_MovePauseClear( ebw->BongTreeObj );
		//ゆれるアニメ開始
		FieldOBJ_DrawStatusSet( ebw->BongTreeObj, 1 );
		//カウンタ初期化
		ebw->SwayCount = 0;
		ebw->SwayFrame = SWAY_FRAME;
		//シーケンス変更
		ebw->Seq = SEQ_BONG_SWAY;
		//揺らすＳＥ
		Snd_SePlay(SEQ_SE_GS_KI_YURERU);
		break;
	case SEQ_BONG_SWAY:
		//ゆれるアニメ
		ebw->SwayFrame--;
		if (ebw->SwayFrame <= 0){
			ebw->SwayCount++;
			ebw->SwayFrame = SWAY_FRAME;
		}

		if (ebw->SwayCount>=SWAY_COUNT){	//終了
			//アニメ戻す(ドロー関数読んでないから、実際は変わらないのだが)
			FieldOBJ_DrawStatusSet( ebw->BongTreeObj, 0 );
			//ポーズ
			FieldOBJ_MovePause( ebw->BongTreeObj );

			//シーケンス分岐
			if (BongSys_IsGrow(fsys, ebw->BongTreeObj)){
				//内部データ書き換え
				BongSys_Take(fsys,  ebw->BongTreeObj);
				*(ebw->ReturnCode) = 1;
				ebw->Seq = SEQ_BONG_INIT;
			}else{
				*(ebw->ReturnCode) = 0;
				ebw->Seq = SEQ_BONG_END;
			}
		}
		break;
	case SEQ_BONG_INIT:
		{
			int dir;
			//自機の向きを取得して、木の実を飛ばす方向を決定
			dir = Player_DirGet( fsys->player );
			//必要パラメータセット
			ebw->AddVec.x = 0;
			ebw->AddVec.z = 0;
			ebw->AddVec.y = 0;
			switch(dir){
			case DIR_UP:
				ebw->AddVec.z = FX32_ONE;
				break;
			case DIR_DOWN:
				ebw->AddVec.z = -FX32_ONE;
				break;
			case DIR_RIGHT:
				ebw->AddVec.x = -FX32_ONE;
				break;
			case DIR_LEFT:
				ebw->AddVec.x = FX32_ONE;
				break;
			}
		}
		ebw->Seq = SEQ_BONG_FRUIT_ADD;
		break;
	case SEQ_BONG_FRUIT_ADD:
		{
			int x,z;
			int bong_type;
			//ボングリの木の位置を取得
			Player_DirFrontGridPosGet( fsys->player, &x, &z );
			//フィールドＯＢＪ追加
			bong_type = BongSys_GetBongType(fsys, ebw->BongTreeObj) - 1;
			GF_ASSERT(bong_type >= 0);
			ebw->FldObj = AddFruitOBJ( fsys->fldobjsys, BONGURI01F + bong_type, x, z);
			{
				VecFx32 vec;
				FieldOBJ_VecPosGet( ebw->FldObj, &vec );
				vec.y+= START_Y_OFS;
				FieldOBJ_VecPosSet( ebw->FldObj, &vec );
			}
		}
		ebw->Seq = SEQ_BONG_FRUIT_ADD_WAIT;
		break;
	case SEQ_BONG_FRUIT_ADD_WAIT:
		//実の登録を待ち
		if ( !FieldOBJ_BlActAddPracFlagCheck(ebw->FldObj) ){
			//ボングリの木を実の生っていない木に変更
			FieldOBJ_BlActDummyDrawReset( ebw->BongTreeObj, BONGURI );
			ebw->Seq = SEQ_BONG_TREE_CHANGE_WAIT;
		}
		break;
	case SEQ_BONG_TREE_CHANGE_WAIT:
		//ボングリの木の登録を待ち
		if (!FieldOBJ_BlActAddPracFlagCheck(ebw->BongTreeObj)){
			ebw->ShotFrame = BONG_SHOT_FRAME;
			//アニメ切り替え
			FieldOBJ_DrawStatusSet( ebw->BongTreeObj, 2 );
			//ポーズ解除
			FieldOBJ_MovePauseClear( ebw->BongTreeObj );
			//シーケンス変更
			ebw->Seq = SEQ_BONG_SHOT_ANM;
		}
		break;
	case SEQ_BONG_SHOT_ANM:
		ebw->ShotFrame--;
		if (ebw->ShotFrame <= 0){
			//実を表示
			FieldOBJ_StatusBit_OFF(ebw->FldObj, FLDOBJ_STA_BIT_VANISH);
			//アニメカウント初期化
			ebw->AnmCount = 0;

			Snd_SePlay( SEQ_SE_GS_FW255E );

			//ボングリ飛ばしアニメシーケンスへ
			ebw->Seq = SEQ_BONG_FRUIT_ANM;
		}
		break;
	case SEQ_BONG_FRUIT_ANM:
		//ボングリ飛ばしアニメ
		if ( FruitAnmMain(ebw) ){		//終了？
			//アニメ切り替え
			FieldOBJ_DrawStatusSet( ebw->BongTreeObj, 0 );
			//次のシーケンスへ
			ebw->Seq = SEQ_BONG_END;
		}
		break;
	case SEQ_BONG_END:
		//ポーズ
		FieldOBJ_MovePause( ebw->BongTreeObj );
		sys_FreeMemoryEz(ebw);
		return TRUE;
	}
	return FALSE;
}

//--------------------------------------------------------------
/**
 * ボングリの実フィールドOBJ追加
 * @param	fos			FIELD_OBJ_SYS_PTR
 * @param	obj			OBJコード。HERO等
 * @param	x			グリッドX座標
 * @param	z			グリッドZ座標
 * @retval	FIELD_OBJ_PTR
 */
//--------------------------------------------------------------
static FIELD_OBJ_PTR AddFruitOBJ( CONST_FIELD_OBJ_SYS_PTR fos,
		int obj, int x, int z)
{
	FIELD_OBJ_PTR fldobj;

	fldobj = FieldOBJ_AddHMake( fos, x, z, DIR_UP, obj, MV_DMY, ZONE_ID_NOTHING );
	GF_ASSERT( fldobj != NULL && "player init obj add error" );

	FieldOBJ_OBJIDSet( fldobj, FLDOBJ_ID_BONGURI_F );
	FieldOBJ_EventTypeSet( fldobj, 0 );
	FieldOBJ_EventFlagSet( fldobj, 0 );
	FieldOBJ_MoveLimitXSet( fldobj, MOVE_LIMIT_NOT );
	FieldOBJ_MoveLimitZSet( fldobj, MOVE_LIMIT_NOT );
	FieldOBJ_StatusBit_ON( fldobj, BONG_FLDOBJ_INIT_STA_BIT_ON );
	FieldOBJ_StatusBit_OFF( fldobj, BONG_FLDOBJ_INIT_STA_BIT_OFF );
	FieldOBJ_StatusBitSet_HeightExpand( fldobj, TRUE );
	//バニッシュ
	FieldOBJ_StatusBit_ON(fldobj, FLDOBJ_STA_BIT_VANISH);
	return fldobj;
}

//--------------------------------------------------------------
/**
 * ボングリアニメメイン
 * @param	*ebw			ワークポインタ
 * @retval	BOOL			TRUEで終了
 */
//--------------------------------------------------------------
static BOOL FruitAnmMain(EV_BONG_FRUIT_WORK * ebw)
{
	//実のＹ座標変更
	{
		VecFx32 vec;
		FieldOBJ_VecPosGet( ebw->FldObj, &vec );

		vec.y+= (FX32_ONE*FlyY[ebw->AnmCount]);
		vec.x+= ebw->AddVec.x;
		vec.z+= ebw->AddVec.z;

		FieldOBJ_VecPosSet( ebw->FldObj, &vec );

		if (++ebw->AnmCount >= FRUIT_FLY_ANM_SYNC){
			//ＯＢＪ解放
			FieldOBJ_Delete( ebw->FldObj );
			return TRUE;
		}
	}
	return FALSE;
}


//--------------------------------------------------------------
/**
 * 主人公の木揺らしアニメ
 * @param	event			イベントポインタ
 * @retval	BOOL	TRUEでイベント終了
 */
//--------------------------------------------------------------
static BOOL GMEVENT_ShakePlayer(GMEVENT_CONTROL * event)
{
	FIELDSYS_WORK * fsys = FieldEvent_GetFieldSysWork(event);
	FIELD_OBJ_PTR fldobj = Player_FieldOBJGet( fsys->player );
	int *seq = FieldEvent_GetSeqWork(event);
	int *frame = FieldEvent_GetSpecialWork(event);

	switch(*seq){
	case 0:
		FieldOBJ_MovePauseClear( fldobj );
		(*seq)++;
		break;
	case 1:
		if( FieldOBJ_AcmdSetCheck(fldobj) == TRUE ){
			FieldOBJ_AcmdEnd( fldobj );
			Player_RequestSet( fsys->player, HERO_REQBIT_SHAKE );
			Player_Request( fsys->player );
			FieldOBJ_DrawStatusSet( fldobj, DRAW_STA_SHAKE );
			*frame = 0;
			(*seq)++;
		}
		break;
	case 2:
		(*frame)++;
		if( (*frame > PLAYER_SHAKE_FRAME)&&(FieldOBJ_AcmdSetCheck(fldobj) == TRUE) ){
			int form;
			u32 req_bit;
			FieldOBJ_AcmdEnd( fldobj );
			form = Player_FormGet( fsys->player );
			req_bit = Player_FormRequestGet( form );
			Player_RequestSet( fsys->player, req_bit );
			Player_Request( fsys->player );
			(*seq)++;
		}
		break;
	case 3:
		FieldOBJ_MovePause( fldobj );
		sys_FreeMemoryEz(frame);
		return TRUE;
	}

	return FALSE;
}